﻿using System;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Microsoft.Phone.Controls;

namespace Huyn
{
    public class PageRotationBehavior : Behavior<PhoneApplicationPage>
    {
        internal static readonly CacheMode BitmapCacheMode = new BitmapCache();
        private Storyboard _story;
        private CacheMode _cacheMode;

        private bool _isHitTestVisible;
        private PageOrientation _lastOrientation;

        protected override void OnAttached()
        {
            base.OnAttached();

            var planeProjection = new PlaneProjection { CenterOfRotationX = 0.5, CenterOfRotationY = 0.5 };
            AssociatedObject.Projection = planeProjection;
            AssociatedObject.OrientationChanged += AssociatedObjectOrientationChanged;
            _lastOrientation = AssociatedObject.Orientation;
        }


        private void InitAnim()
        {
            _cacheMode = AssociatedObject.CacheMode;
            if (!(_cacheMode is BitmapCache))
            {
                AssociatedObject.CacheMode = BitmapCacheMode;
            }
            _isHitTestVisible = AssociatedObject.IsHitTestVisible;
            if (_isHitTestVisible)
            {
                AssociatedObject.IsHitTestVisible = false;
            }
        }

        protected void Anim(int rotationfrom, int rotationto)
        {
            InitAnim();

            if (_story == null)
                _story = CreateStoryboard();

            var rotationanim = ((DoubleAnimationUsingKeyFrames)_story.Children[0]);
            rotationanim.KeyFrames[0].Value = rotationfrom;
            rotationanim.KeyFrames[1].Value = rotationto;

            _story.Completed += StoryCompleted;
            try
            {
                _story.Begin();
            }
            catch
            {
            }
        }

        private void StoryCompleted(object sender, EventArgs e)
        {
            CompleteAnim();
            _story.Completed -= StoryCompleted;
        }

        private Storyboard CreateStoryboard()
        {
            var story = new Storyboard { FillBehavior = FillBehavior.Stop };

            var rotation = new DoubleAnimationUsingKeyFrames();
            Storyboard.SetTarget(rotation, (AssociatedObject.Projection));
            Storyboard.SetTargetProperty(rotation, new PropertyPath(PlaneProjection.RotationZProperty));
            rotation.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0)), Value = 180 });
            rotation.KeyFrames.Add(new EasingDoubleKeyFrame
            {
                EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseOut, Exponent = 1 },
                KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(250)),
                Value = 0
            });

            story.Children.Add(rotation);
            var opacity = new DoubleAnimationUsingKeyFrames();
            Storyboard.SetTarget(opacity, AssociatedObject);
            Storyboard.SetTargetProperty(opacity, new PropertyPath(UIElement.OpacityProperty));
            opacity.KeyFrames.Add(new EasingDoubleKeyFrame { KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0)), Value = 0 });
            opacity.KeyFrames.Add(new EasingDoubleKeyFrame
            {
                EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseOut, Exponent = 1 },
                KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(250)),
                Value = 1
            });

            story.Children.Add((opacity));
            return story;
        }

        private void CompleteAnim()
        {
            if (!(_cacheMode is BitmapCache))
            {
                AssociatedObject.CacheMode = _cacheMode;
            }
            if (_isHitTestVisible)
            {
                AssociatedObject.IsHitTestVisible = _isHitTestVisible;
                return;
            }
            AssociatedObject.IsHitTestVisible = true;
        }

        private void AssociatedObjectOrientationChanged(object sender, OrientationChangedEventArgs e)
        {
            var newOrientation = e.Orientation;
            switch (newOrientation)
            {
                case PageOrientation.Landscape:
                case PageOrientation.LandscapeRight:
                    // Come here from PortraitUp (i.e. clockwise) or LandscapeLeft?
                    if (_lastOrientation == PageOrientation.PortraitUp)
                        Anim(-90, 0);
                    else
                        Anim(180, 0);
                    break;
                case PageOrientation.LandscapeLeft:
                    // Come here from LandscapeRight or PortraitUp?
                    if (_lastOrientation == PageOrientation.LandscapeRight)
                        Anim(-180, 0);
                    else
                        Anim(90, 0);
                    break;
                case PageOrientation.Portrait:
                case PageOrientation.PortraitUp:
                    // Come here from LandscapeLeft or LandscapeRight?
                    if (_lastOrientation == PageOrientation.LandscapeLeft)
                        Anim(-90, 0);
                    else
                        Anim(90, 0);
                    break;
                default:
                    break;
            }


            _lastOrientation = newOrientation;
        }


        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.OrientationChanged -= AssociatedObjectOrientationChanged;
        }
    }
}